package com.shinbada.modules.competitor.service;

import com.google.common.collect.Maps;
import com.shinbada.core.persistence.Page;
import com.shinbada.core.service.CrudService;
import com.shinbada.excel.ExcelKit;
import com.shinbada.excel.handler.DefaultExcelReadStrategyHandlerV3;
import com.shinbada.excel.modle.CheckResult;
import com.shinbada.excel.modle.ImportExcelResult;
import com.shinbada.excel.modle.StrategyCheckService;
import com.shinbada.excel.modle.UploadModle;
import com.shinbada.modules.competitor.entity.CompetitorNoumenon;
import com.shinbada.modules.competitor.entity.CompetitorNoumenonDataItem;
import com.shinbada.modules.competitor.entity.CompetitorProductDataItem;
import com.shinbada.modules.competitor.entity.CompetitorProductSeries;
import com.shinbada.modules.competitor.entity.DTO.CompetitorNoumenonDTO;
import com.shinbada.modules.competitor.entity.DTO.ParamModelSelectionDTO;
import com.shinbada.modules.competitor.entity.VO.CompetitorDataItemVO;
import com.shinbada.modules.competitor.entity.VO.CompetitorNoumenonResultVO;
import com.shinbada.modules.competitor.entity.VO.CompetitorProductDataItemVO;
import com.shinbada.modules.competitor.entity.VO.ConditionTreeVO;
import com.shinbada.modules.competitor.mapper.CompetitorNoumenonMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 本体Service
 *
 * @author initcap
 * @version 2021-08-11
 */
@Service
@Transactional(readOnly = true)
public class CompetitorNoumenonService extends CrudService<CompetitorNoumenonMapper, CompetitorNoumenon> implements StrategyCheckService<CompetitorNoumenon> {

    @Autowired
    private CompetitorProductSeriesService competitorProductSeriesService;

    @Autowired
    private CompetitorNoumenonDataItemService competitorNoumenonDataItemService;

    @Autowired
    private CompetitorProductDataItemService competitorProductDataItemService;

    private Map<String, String> keys;

    private Map<String, String> dataItemMap;

    @Override
    public CompetitorNoumenon get(String id) {
        return super.get(id);
    }

    @Override
    public List<CompetitorNoumenon> findList(CompetitorNoumenon competitorNoumenon) {
        return super.findList(competitorNoumenon);
    }

    @Override
    public Page<CompetitorNoumenon> findPage(Page<CompetitorNoumenon> page, CompetitorNoumenon competitorNoumenon) {
        return super.findPage(page, competitorNoumenon);
    }

    @Transactional(readOnly = false)
    @Override
    public void save(CompetitorNoumenon competitorNoumenon) {
        super.save(competitorNoumenon);
    }

    @Transactional(readOnly = false)
    @Override
    public void delete(CompetitorNoumenon competitorNoumenon) {
        super.delete(competitorNoumenon);
    }

    @Transactional(readOnly = false)
    @SneakyThrows
    public ImportExcelResult<CompetitorNoumenon> uploadExcel(MultipartFile file, UploadModle modle) {
        // 1. 准备提前数据
        readExcelInit();
        // 2. 添加数据处理器
        DefaultExcelReadStrategyHandlerV3<CompetitorNoumenon> excelReadHandler = new DefaultExcelReadStrategyHandlerV3<>(modle, this);
        // 3. 执行导入
        ExcelKit.$Import(CompetitorNoumenon.class).readXlsx(file.getInputStream(), excelReadHandler);
        // 4. 获得导入结果集
        ImportExcelResult<CompetitorNoumenon> importExcelResult = excelReadHandler.results();
        // 5. 批量添加成功数据
        importExcelResult.getSuccessList().forEach(this::save);
        // 返回结果,成功的数据不返回了，影响响应速度
        importExcelResult.setSuccessList(null);
        return importExcelResult;

    }

    /**
     * @param entity 实体类
     * @return 这个key的获取决定了，在Excel导入的时候需要校验的唯一标准
     */
    private String getReadExcelKey(CompetitorNoumenon entity) {
        return entity.getId() + entity.getRemarks();
    }

    private void readExcelInit() {
        // 获取到现在数据库中的所有数据
        List<CompetitorNoumenon> db = mapper.findAllList(new CompetitorNoumenon());
        this.keys = Maps.newHashMapWithExpectedSize(db.size());
        // 转换键配置,请根据必要条件实现，直接使用会有问题
        db.forEach(entity -> this.keys.put(getReadExcelKey(entity), entity.getId()));
    }

    @Override
    public CheckResult readAndCheck(CompetitorNoumenon entity) {
        // 验证重复数据,请根据必要条件实现，直接使用会有问题
        String key = getReadExcelKey(entity);
        if (this.keys.containsKey(key)) {
            entity.setId(this.keys.get(key));
            return CheckResult.cover(key);
        }
        // 添加数据
        this.keys.put(key, "");
        return CheckResult.pass(key);
    }

    public List<CompetitorNoumenonResultVO> getNoumenonTreeStructure(CompetitorNoumenonDTO competitorNoumenonDTO) {
        return mapper.getNoumenonTreeStructure(competitorNoumenonDTO);
    }

    public List<ConditionTreeVO> conditionTree(String brandId) {
        // 根据品牌id 获取系列一级树
        List<CompetitorProductSeries> seriesList = competitorProductSeriesService.getSeriesListByBrandId(brandId);
        List<ConditionTreeVO> conditionTreeVOArrayList = new ArrayList<>();
        // 系列第一层获取
        for (int i = 0; i < seriesList.size(); i++) {
            ConditionTreeVO conditionTreeVO = new ConditionTreeVO();
            conditionTreeVO.setName(seriesList.get(i).getName());
            conditionTreeVO.setId(seriesList.get(i).getId());
            conditionTreeVOArrayList.add(conditionTreeVO);
            // 电器级别 数据存储
            CompetitorProductDataItem competitorProductDataItem = new CompetitorProductDataItem();
            competitorProductDataItem.setName("电器级别（CC/CB/PC）");
            competitorProductDataItem.setType(CompetitorProductDataItem.ATS_NOUMENON);
            //
            List<CompetitorNoumenonDataItem> competitorNoumenonDataItemList = competitorNoumenonDataItemService.getTypeAndNameByDataItemValue(competitorProductDataItem);
            List<CompetitorNoumenonDataItem> collect = competitorNoumenonDataItemList.stream().collect(Collectors.collectingAndThen(
                    Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CompetitorNoumenonDataItem::getNoumenonValue))), ArrayList::new
            ));
            dataManage(conditionTreeVOArrayList, collect, seriesList.get(i).getId());
        }
        return dataDistinct(conditionTreeVOArrayList);
    }

    /**
     * 电器级别数据以及 规格(壳架电流)树型结构数据追加
     *
     * @param conditionTreeVOArrayList 树形结构集合
     * @param collect                  处理数据集合
     * @param id                       上级(系列)id
     */
    private void dataManage(List<ConditionTreeVO> conditionTreeVOArrayList, List<CompetitorNoumenonDataItem> collect, String id) {
        // 电器级别获取
        for (CompetitorNoumenonDataItem competitorNoumenonDataItem : collect) {
            ConditionTreeVO conditionTreeVO1 = new ConditionTreeVO();
            conditionTreeVO1.setName(competitorNoumenonDataItem.getNoumenonValue());
            conditionTreeVO1.setId(competitorNoumenonDataItem.getId());
            conditionTreeVO1.setPid(id);
            conditionTreeVOArrayList.add(conditionTreeVO1);
            // 壳架电流 数据存储
            CompetitorProductDataItem electricity = new CompetitorProductDataItem();
            electricity.setName("规格");
            electricity.setType(CompetitorProductDataItem.ATS_NOUMENON);
            List<CompetitorNoumenonDataItem> electricityList = competitorNoumenonDataItemService.getTypeAndNameByDataItemValue(electricity);
            List<CompetitorNoumenonDataItem> competitorNoumenonDataItems = electricityList.stream().collect(Collectors.collectingAndThen(
                    Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CompetitorNoumenonDataItem::getNoumenonValue))), ArrayList::new
            ));
            // 规格
            for (CompetitorNoumenonDataItem competitorNoumenonDataItem1 : competitorNoumenonDataItems) {
                ConditionTreeVO conditionTreeVO2 = new ConditionTreeVO();
                conditionTreeVO2.setName(competitorNoumenonDataItem1.getNoumenonValue());
                conditionTreeVO2.setId(competitorNoumenonDataItem1.getId());
                conditionTreeVO2.setPid(competitorNoumenonDataItem.getId());
                conditionTreeVOArrayList.add(conditionTreeVO2);
            }
        }
    }

    /**
     * 数据去重校验  名称+id 组成 key 作为唯一标识
     *
     * @param conditionTreeVOArrayList 处理数据集合
     * @return
     */
    private List<ConditionTreeVO> dataDistinct(List<ConditionTreeVO> conditionTreeVOArrayList) {
        return conditionTreeVOArrayList.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(
                        conditionTreeVO -> conditionTreeVO.getName() + ";" + conditionTreeVO.getId() + ";" + conditionTreeVO.getPid()))), ArrayList::new
        ));
    }

    /**
     * 根据参数选型所选择的值以及名称获取结构数据
     *
     * @param paramModelSelectionDTOList 参数选型参数以及结果
     * @return
     */
    public List<CompetitorNoumenonResultVO> modelSelection(List<ParamModelSelectionDTO> paramModelSelectionDTOList) {
        // 根据类型获取数据项
        List<CompetitorProductDataItem> competitorProductDataItemList = competitorProductDataItemService.selectDataItemByType(CompetitorProductDataItem.ATS_NOUMENON);
        this.dataItemMap = competitorProductDataItemList.stream().collect(Collectors.toMap(CompetitorProductDataItem::getName, CompetitorProductDataItem::getId));
        // 获取数据项id 追加到集合中
        paramModelSelectionDTOList.stream().forEach(paramModelSelectionDTO -> paramModelSelectionDTO.setId(this.dataItemMap.get(paramModelSelectionDTO.getName())));
        // 根据集合获取本体ids
        String[] noumenonIds = competitorNoumenonDataItemService.selectNoumenonByItemIdAndValue(paramModelSelectionDTOList);
        // 根据ids获取本体数据结构
        List<CompetitorNoumenonResultVO> list = mapper.getNoumenonTreeStructureByNoumenonIds(noumenonIds);
        // 集合转map
        listToMap(list);
        return list;
    }

    /**
     * 竞品推荐
     * @return
     * @param competitorNoumenonDTO
     */
    public List<CompetitorNoumenonResultVO> competitorRecommend(CompetitorNoumenonDTO competitorNoumenonDTO) {
        // 获取重要参数数据项以及数据项数据值
        List<CompetitorNoumenonResultVO> noumenonTreeStructure = mapper.getNoumenonTreeStructure(competitorNoumenonDTO);
        List<ParamModelSelectionDTO> paramModelSelectionDTOList = new ArrayList<>();
        for (CompetitorNoumenonResultVO competitorNoumenonResultVO:noumenonTreeStructure) {
            List<CompetitorDataItemVO> competitorDataItemVOList = competitorNoumenonResultVO.getCompetitorDataItemVOS();

            for (CompetitorDataItemVO competitorDataItemVO : competitorDataItemVOList) {
                ParamModelSelectionDTO paramModelSelectionDTO = new ParamModelSelectionDTO();
                paramModelSelectionDTO.setId(competitorDataItemVO.getDataItemId());
                paramModelSelectionDTO.setName(competitorDataItemVO.getDataItemName());
                paramModelSelectionDTO.setValue(competitorDataItemVO.getValue());
                paramModelSelectionDTOList.add(paramModelSelectionDTO);
            }
        }
        String[] noumenonIds = competitorNoumenonDataItemService.selectNoumenonByItemIdAndValue(paramModelSelectionDTOList);
        // 根据ids获取本体数据结构
        List<CompetitorNoumenonResultVO> list = mapper.getNoumenonTreeStructureByNoumenonIds(noumenonIds);
        // 集合转map
        listToMap(list);
        return list;
    }

    /**
     * 集合数据转换成map数据
     * @param list
     */
    private void listToMap(List<CompetitorNoumenonResultVO> list) {
        for (CompetitorNoumenonResultVO competitorNoumenonResultVO : list) {
            Map<String, CompetitorDataItemVO> map = competitorNoumenonResultVO.getCompetitorDataItemVOS().stream()
                    .collect(Collectors.toMap(CompetitorDataItemVO::getDataItemId, o -> o, (o, o1) -> o));
            competitorNoumenonResultVO.setCompetitorDataItemVOMap(map);
            competitorNoumenonResultVO.setCompetitorDataItemVOS(null);
        }
    }

    /**
     * 竞品相同项移除
     * @param competitorNoumenonDTO
     * @return
     */
    public List<CompetitorProductDataItemVO> identicalEntry(CompetitorNoumenonDTO competitorNoumenonDTO) {
        // 跟据产品型号获取产品树型结构数据
        List<CompetitorNoumenonResultVO> noumenonTreeStructure = mapper.getNoumenonTreesStructure(competitorNoumenonDTO);

        Map<String, List<CompetitorDataItemVO>> map = new HashMap<>();
        // 跟据key  获取数据集
        for (CompetitorNoumenonResultVO competitorNoumenonResultVO: noumenonTreeStructure){
            List<CompetitorDataItemVO> competitorDataItemVOS = competitorNoumenonResultVO.getCompetitorDataItemVOS();
            for (CompetitorDataItemVO competitorDataItemVO:competitorDataItemVOS){
                if (map.containsKey(competitorDataItemVO.getDataItemId())){
                    map.get(competitorDataItemVO.getDataItemId()).add(competitorDataItemVO);
                }else {
                    List<CompetitorDataItemVO> competitorDataItemVOList = new ArrayList<>();
                    competitorDataItemVOList.add(competitorDataItemVO);
                    map.put(competitorDataItemVO.getDataItemId(),competitorDataItemVOList);
                }
            }
        }

        // 将数据结构转换成map
        listToMap(noumenonTreeStructure);
        // 跟据左侧列 树型结构获取参数  获取属性结构
        List<CompetitorProductDataItemVO> treeStructure = competitorProductDataItemService.getTreeStructure(CompetitorProductDataItem.ATS_NOUMENON, String.valueOf(competitorNoumenonDTO.getParameterType()));
        // 遍历属性结构
        List<String> itemIdList = new ArrayList<>();
        for (CompetitorProductDataItemVO dataItemVO:treeStructure ) {
            // 跟据属性结构dataItemId 比对value
            List<CompetitorDataItemVO> competitorDataItemVOList = map.get(dataItemVO.getDataItemId());
            Map<String, String> collect = competitorDataItemVOList.stream().collect(Collectors.toMap(CompetitorDataItemVO::getValue, CompetitorDataItemVO::getDataItemId));
            if (collect.size()>1){
                // 相同返回item_id 放入数组中
                itemIdList.add(dataItemVO.getDataItemId());
            }
        }
        String[] array = new String[itemIdList.size()];
        // 跟据itemIds 获取不在这里面得属性结构
        List<CompetitorProductDataItemVO> disaffinityDataItem = competitorProductDataItemService.getDisaffinityDataItem(array,CompetitorProductDataItem.ATS_NOUMENON,String.valueOf(competitorNoumenonDTO.getParameterType()));

        return disaffinityDataItem;
    }
}
